package com.xbongbong.paas.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.sys.help.PackageHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.log.entity.OperateDetailLogEntity;
import com.xbongbong.paas.log.entity.OperateLogEntity;
import com.xbongbong.paas.log.model.OperateDetailLogModel;
import com.xbongbong.paas.log.model.OperateLogModel;
import com.xbongbong.paas.pojo.ButtonPojo;
import com.xbongbong.paas.service.OperateLogService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.PageHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.CommonConstant;
import com.xbongbong.pro.enums.errorcodes.LogErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.log.enums.DetailLogEnum;
import com.xbongbong.pro.log.pojo.DetailLogComplexPojo;
import com.xbongbong.pro.log.pojo.DetailLogDataPojo;
import com.xbongbong.pro.log.pojo.DetailLogPojo;
import com.xbongbong.pro.log.pojo.OperateTypePojo;
import com.xbongbong.pro.log.pojo.dto.FormSearchListDTO;
import com.xbongbong.pro.log.pojo.dto.OperateDetailLogDTO;
import com.xbongbong.pro.log.pojo.dto.OperateLogConditionDTO;
import com.xbongbong.pro.log.pojo.dto.OperateLogListDTO;
import com.xbongbong.pro.log.pojo.vo.FormSearchListVO;
import com.xbongbong.pro.log.pojo.vo.FormSearchVO;
import com.xbongbong.pro.log.pojo.vo.OperateDetailLogVO;
import com.xbongbong.pro.log.pojo.vo.OperateLogConditionVO;
import com.xbongbong.pro.log.pojo.vo.OperateLogListVO;
import com.xbongbong.pro.log.pojo.vo.OperateLogVO;
import com.xbongbong.pro.statistic.result.pojo.TitlePojo;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.enums.ListOptionTabEnum;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 操作日志服务实现
 * @author kaka
 * @date 2019/1/22 20:16
 * @since v1.0
 * @version v1.0
 */
@Service("operateLogService")
public class OperateLogServiceImpl implements OperateLogService {

    private static final Logger LOG = LoggerFactory.getLogger(OperateLogServiceImpl.class);

    @Resource
    public OperateLogModel operateLogModel;
    @Resource
    private OperateDetailLogModel operateDetailLogModel;
    @Resource
    private PackageHelp packageHelp;

    /**
     * 表单列表
     *
     * @param formSearchListDTO 关联业务DTO
     * @return 表单VO
     * @throws XbbException 业务异常
     */
    @Override
    public FormSearchListVO getFormSearchList(FormSearchListDTO formSearchListDTO) throws XbbException {
        FormSearchListVO formSearchListVO = new FormSearchListVO();
        List<FormSearchVO> list = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<OperateModuleTypeEnum> operateModuleTypeEnumList = OperateModuleTypeEnum.getAllEnum();
        operateModuleTypeEnumList.forEach(operateModuleTypeEnum -> {
            FormSearchVO formSearchVO = new FormSearchVO();
            formSearchVO.setModuleType(operateModuleTypeEnum.getCode());
            formSearchVO.setName(operateModuleTypeEnum.getName());
            // 筛选居然按moduleName查询的，太骚了
            if (Objects.equals(operateModuleTypeEnum, OperateModuleTypeEnum.INSTOCK.getCode())) {
                formSearchVO.setName(XbbRefTypeEnum.OTHER_INSTOCK.getName());
            }
            list.add(formSearchVO);
        });
        formSearchListVO.setList(list);
        return formSearchListVO;
    }
    
    @Override
    public OperateLogListVO list(OperateLogListDTO operateLogListDTO) throws XbbException {
        OperateLogListVO operateLogListVO = new OperateLogListVO();
        Map<String, Object> param = BeanUtil.convertBean2Map(operateLogListDTO, true);
        // 排序因为有注入问题不能通过外部传入
        param.put("orderByStr", "addTime DESC");

        try {
            PageHelper pageHelper = new PageHelper(operateLogListDTO.getPage(), operateLogListDTO.getPageSize());
            List<OperateLogEntity> operateLogList = (List<OperateLogEntity>) PageHelperUtil.getEntityListNoTotal(param, pageHelper, operateLogModel);

            List<OperateLogVO> operateLogVOs = new ArrayList<>();
            for (OperateLogEntity operateLog : operateLogList) {
                OperateLogVO operateLogVO = new OperateLogVO();
                BeanUtil.copyProperties(operateLog, operateLogVO);
                String addTimeStr = DateUtil.getString(operateLog.getAddTime(), new SimpleDateFormat("yyyy-MM-dd HH:mm"));
                operateLogVO.setAddTime(addTimeStr);
                operateLogVOs.add(operateLogVO);
            }
            //返回导出按钮权限,旗舰版支持
            List<ButtonPojo> topPermissions = new ArrayList<>();
            if(packageHelp.isUltimateWithFeeType(operateLogListDTO.getCorpid())){
                topPermissions.add(new ButtonPojo(ListOptionTabEnum.EXPORT));
                operateLogListVO.setTopPermissions(topPermissions);
            }
            operateLogListVO.setList(operateLogVOs);
            operateLogListVO.setPageHelper(pageHelper);
        } catch (Exception e) {
            LOG.error("OperateLogServiceImpl.list 执行出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }

        return operateLogListVO;
    }

    @Override
    public OperateLogConditionVO getCondition(OperateLogConditionDTO operateLogConditionDTO) throws XbbException {
        OperateLogConditionVO operateLogConditionVO = new OperateLogConditionVO();
        List<OperateTypePojo> operateTypePojoList = getOperateTypePojoList();

        operateLogConditionVO.setOperateTypeList(operateTypePojoList);
        return operateLogConditionVO;
    }

    @Override
    public OperateDetailLogVO detail(OperateDetailLogDTO operateDetailLogDTO) throws XbbException {
        OperateDetailLogEntity detailLogEntity = operateDetailLogModel.getByOperateLogId(operateDetailLogDTO.getCorpid(), operateDetailLogDTO.getOperateLogId());
        if (detailLogEntity == null) {
            throw new XbbException(LogErrorCodeEnum.API_ERROR_391001, LogErrorCodeEnum.API_ERROR_391001.getMsg());
        }
        Integer operateType = operateDetailLogDTO.getOpType();
        OperateTypeEnum operateTypeEnum = OperateTypeEnum.getByCode(operateType);
        if (OperateTypeEnum.UNKNOWN == operateTypeEnum) {
            throw new XbbException(LogErrorCodeEnum.API_ERROR_391003, LogErrorCodeEnum.API_ERROR_391003.getMsg());
        }
        JSONArray detailArr = JsonHelperUtil.parseArray(detailLogEntity.getDetailArr());
        List<JSONObject> infoArr = JsonHelperUtil.parseArray(detailLogEntity.getInfoArr(), JSONObject.class);

        // 复杂详情
        Integer complexDetailFlag = detailLogEntity.getComplexDetail();
        if(Objects.nonNull(complexDetailFlag)){
            return dealComplexDetail(complexDetailFlag,detailArr);
        }
        Integer tabFlag = 0;
        List<DetailLogDataPojo> logList = new ArrayList<>();
        if (detailArr.size() > 0) {
            //字段、更改前、更改后
            List<TitlePojo> title = new ArrayList<>();
            title.add(new TitlePojo(DetailLogEnum.NAME.getAlias(), DetailLogEnum.NAME.getName()));
            title.add(new TitlePojo(DetailLogEnum.UPDATA_BEFORE.getAlias(), DetailLogEnum.UPDATA_BEFORE.getName()));
            title.add(new TitlePojo(DetailLogEnum.UPDATA_AFTER.getAlias(), DetailLogEnum.UPDATA_AFTER.getName()));

            logList.add(new DetailLogDataPojo(title, detailArr));
        } else if (infoArr.size() > 0) {
            //tab、字段名、更改内容
            String titleKey = DetailLogEnum.CONTENT.getAlias();
            for (JSONObject item : infoArr) {
                String tab = item.getString("tab");
                if (StringUtil.isNotEmpty(tab)) {
                    tabFlag = 1;
                }
                String titleValue = item.getString("title");
                List<TitlePojo> title = Arrays.asList(new TitlePojo(titleKey, titleValue));
                JSONArray data = new JSONArray();
                data.add(item);
                DetailLogDataPojo detailLogDataPojo = new DetailLogDataPojo(tab, title, data);
                logList.add(detailLogDataPojo);
            }
        }
        OperateDetailLogVO operateDetailLogVo = new OperateDetailLogVO(tabFlag, logList);
        return operateDetailLogVo;
    }

    private void dealComplexLog(List<DetailLogComplexPojo> complexLogList) {
        if (complexLogList.isEmpty()) {
            return;
        }
        for (DetailLogComplexPojo detailLogComplexPojo : complexLogList) {
            if (Objects.nonNull(detailLogComplexPojo.getDetailList()) && detailLogComplexPojo.getDetailList().isEmpty()) {
                detailLogComplexPojo.getDetailList().add(new DetailLogPojo());
            }
        }
    }

    private OperateDetailLogVO dealComplexDetail(Integer complexDetailFlag,JSONArray detailArr){
        if (Objects.nonNull(complexDetailFlag) && Objects.equals(BasicConstant.ONE, complexDetailFlag)) {
            // 标题
            List<TitlePojo> title = new ArrayList<>();
            title.add(new TitlePojo("operate", I18nMessageUtil.getMessage(CommonConstant.OPERATE)));
            title.add(new TitlePojo("operateModule", I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_OPERATION_OBJECT)));
            title.add(new TitlePojo(DetailLogEnum.NAME.getAlias(), DetailLogEnum.NAME.getName()));
            title.add(new TitlePojo(DetailLogEnum.UPDATA_BEFORE.getAlias(), DetailLogEnum.UPDATA_BEFORE.getName()));
            title.add(new TitlePojo(DetailLogEnum.UPDATA_AFTER.getAlias(), DetailLogEnum.UPDATA_AFTER.getName()));
            List<DetailLogComplexPojo> complexLogList = detailArr.toJavaList(DetailLogComplexPojo.class);
            dealComplexLog(complexLogList);
            OperateDetailLogVO operateDetailLogVO = new OperateDetailLogVO();
            operateDetailLogVO.setComplexLogList(complexLogList);
            operateDetailLogVO.setTitle(title);
            return operateDetailLogVO;
        }else if (Objects.nonNull(complexDetailFlag) && Objects.equals(BasicConstant.TWO, complexDetailFlag)) {
            // 标题
            List<TitlePojo> title = new ArrayList<>();
            title.add(new TitlePojo("operateModule", I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_OPERATION_OBJECT)));
            title.add(new TitlePojo(DetailLogEnum.NAME.getAlias(), DetailLogEnum.NAME.getName()));
            title.add(new TitlePojo(DetailLogEnum.UPDATA_BEFORE.getAlias(), DetailLogEnum.UPDATA_BEFORE.getName()));
            title.add(new TitlePojo(DetailLogEnum.UPDATA_AFTER.getAlias(), DetailLogEnum.UPDATA_AFTER.getName()));
            List<DetailLogComplexPojo> complexLogList = detailArr.toJavaList(DetailLogComplexPojo.class);
            dealComplexLog(complexLogList);
            OperateDetailLogVO operateDetailLogVO = new OperateDetailLogVO();
            operateDetailLogVO.setComplexLogList(complexLogList);
            operateDetailLogVO.setTitle(title);
            return operateDetailLogVO;
        }else if(Objects.nonNull(complexDetailFlag) && Objects.equals(BasicConstant.THREE, complexDetailFlag)){
            //目前complexDetailFlag为3的情况用于新增、删除审批评论
            // 标题
            List<TitlePojo> title = new ArrayList<>();
            title.add(new TitlePojo(DetailLogEnum.CONTENT_TEXT.getAlias(), DetailLogEnum.CONTENT_TEXT.getName()));
            title.add(new TitlePojo(DetailLogEnum.PICTURE_COUNT.getAlias(), DetailLogEnum.PICTURE_COUNT.getName()));
            title.add(new TitlePojo(DetailLogEnum.ATTACHMENT_COUNT.getAlias(), DetailLogEnum.ATTACHMENT_COUNT.getName()));
            OperateDetailLogVO operateDetailLogVo = new OperateDetailLogVO(BasicConstant.ZERO, Collections.singletonList(new DetailLogDataPojo(title, detailArr)));
            return operateDetailLogVo;
        }else if(Objects.nonNull(complexDetailFlag) && Objects.equals(BasicConstant.FOUR, complexDetailFlag)){
            //目前complexDetailFlag为4的情况仅用于删除工作流的详情日志页
            // 标题
            List<TitlePojo> title = new ArrayList<>();
            title.add(new TitlePojo(DetailLogEnum.FROM_WORKFLOW_OR_APPROVAL.getAlias(), DetailLogEnum.FROM_WORKFLOW_OR_APPROVAL.getName()));
            title.add(new TitlePojo(DetailLogEnum.TRIGGER_FORM.getAlias(), DetailLogEnum.TRIGGER_FORM.getName()));
            title.add(new TitlePojo(DetailLogEnum.WORKFLOW_VERSION.getAlias(), DetailLogEnum.WORKFLOW_VERSION.getName()));
            OperateDetailLogVO operateDetailLogVo = new OperateDetailLogVO(BasicConstant.ZERO, Collections.singletonList(new DetailLogDataPojo(title, detailArr)));
            return operateDetailLogVo;
        }
        return null;
    }

    //==================== private method ====================

    /**
     * 将 OperateTypeEnum 转化为 操作类型 List<OperateTypePojo>
     * @return List<OperateTypePojo>
     */
    private List<OperateTypePojo> getOperateTypePojoList() {
        List<OperateTypePojo> operateTypePojoList = new ArrayList<>();
        List<OperateTypeEnum> operateTypeEnumList =  OperateTypeEnum.getAllEnum();

        for (OperateTypeEnum operateTypeEnum : operateTypeEnumList) {
            OperateTypePojo operateTypePojo = new OperateTypePojo();
            operateTypePojo.setOpType(operateTypeEnum.getCode());
            operateTypePojo.setName(operateTypeEnum.getName());

            operateTypePojoList.add(operateTypePojo);
        }
        return operateTypePojoList;
    }
}
